const log4js = require('../../../../utils/logUtils');
const logger = log4js.getLogger('sip');

const sip = require("sip");
const util = require("../../../../utils/stringUtils");
const deviceCache = require("../../../../db/deviceCache");
const zlMediaKitApi = require("../../../../service/ZlMediaKitApi");
const xmlUtils = require("./xmlUtils");
const config = require("../../../../db/config");
const clientUtils = require("../clientUtils");
const moment = require("moment");

const TAG = "[inviteHandler]";

module.exports={
    async handle(rq){
        /**
         INVITE sip:34020000001310000131@10.17.28.208:5062;transport=udp SIP/2.0
         Via: SIP/2.0/UDP 10.17.56.26:5061;branch=z9hG4bKkoi7izyx12kwypkk12p1o2p2x
         Call-ID: 839ca0cdfe4fc97777e4e8b5c6164262@10.145.38.36
         From: <sip:34010300002000001251@3401030000>;tag=5b6688c79c0a4aca857ccb77ab42429b-1588813853090
         To: <sip:34020000001310000131@3402000000>
         CSeq: 1 INVITE
         Max-Forwards: 70
         Contact: <sip:34010300002000001251@10.17.56.26:5061>
         Subject: 34020000001310000131:0000007078,34010300002000001251:1
         Content-Length: 218
         Content-Type: application/sdp

         v=0
         o=34020000001310000131 0 0 IN IP4 10.17.56.26
         s=Play
         c=IN IP4 10.17.56.26
         t=0 0
         m=video 21354 RTP/AVP 96 98 97
         a=recvonly
         a=rtpmap:96 PS/90000
         a=rtpmap:98 H264/90000
         a=rtpmap:97 MPEG4/90000
         y=0103008211
         */
        const that = this;
        if (!rq.headers.subject) {
            logger.error('rq.headers.subject 值为空rq=', rq.toString());
            return;
        }

        const cseq = rq.headers.cseq;
        // 34020000001310000131
        const channel_id = rq.headers.subject.split(':')[0];

        // <sip:34010300002000001251@3401030000>;tag=5b6688c79c0a4aca857ccb77ab42429b-1588813853090
        const fromUri = sip.parseUri(rq.headers.from.uri);
        // <sip:34020000001310000131@3402000000>
        const toUri = sip.parseUri(rq.headers.to.uri);
        // SIP/2.0/UDP 10.17.56.26:5061;branch=z9hG4bKkoi7izyx12kwypkk12p1o2p2x
        const via = rq.headers.via;
        const callid = rq.headers['call-id'];
        const obj = util.sipContent2Object(rq.content);
        // 取 s指令
        logger.info(TAG,'[call-id]=', callid, 'sip invite', obj);
        const s = obj.s;
        const t = obj.t;

        // get port
        // obj.m = "m=video 30388 RTP/AVP 96 97 98 99"
        const mediaProtocol = obj.m.split(' ');
        //最后rtp推送到这个端口
        const targetPort = mediaProtocol[1];
        // obj.o = "o=34010300002000002250 0 0 IN IP4 192.168.1.250"
        const targetObj = obj.o.split(' ');
        // 最后rtp推送到这个ip
        const targetIp = targetObj[targetObj.length - 1];

        // 是否已经在推流了， 这里计算key没有使用toUri.user，还需要 观察
        let {pushKey, stream} = xmlUtils.toLocalPushKey(rq.headers,  callid);
        logger.info(TAG,'收到invite, key=', pushKey, '请求推流到:', targetIp, targetPort);
        let target = deviceCache.pushArray[pushKey];

        if (target) {
            if (target.targetIp === targetIp && target.targetPort === targetPort) {
                logger.info(TAG,'已经在推流，准备回应ack, key = ', pushKey);
                await that.videoAck(rq, cseq, fromUri, toUri, via, callid, obj.y, target.localUdpPort, s, t);
            } else {
                logger.info(TAG,'先终止之前的，因为目标地址变了,key = ', target);
                await zlMediaKitApi.stop(target.key);
                delete deviceCache.pushArray[pushKey];
                // 重新生成对象
                deviceCache.pushArray[pushKey] = {
                    playing: false
                };
                target = deviceCache.pushArray[pushKey];
            }
            target.lasttime = new Date();
            // return;
        } else {
            deviceCache.pushArray[pushKey] = {playing: false, lasttime: new Date()};
        }

        let targetCamera = deviceCache.getCameraByChannelId(channel_id);
        logger.info(TAG,"找到目标通道", targetCamera);
        if (targetCamera) {
            // 如果其他进程往目标这推了，要终止
            let tempProcess = xmlUtils.findItemInPushArray(targetCamera);
            if (tempProcess) {
                logger.warn(TAG,'端口被占用:', pushKey, tempProcess.camera_id);
                await zlMediaKitApi.stop(pushKey);
                delete deviceCache.pushArray[pushKey];
            }

            const {upwardUri,upward, self_account } = await clientUtils.generateClientParams();
            // 这里有时候如果发了retTrying,会导致后面的invite无法发出去，暂时不发了
            // logger.info(TAG,'send trying 请求流,key=', pushKey);
            // let retTrying = sip.makeResponse(rq, 100, 'Trying');
            // retTrying.headers.contact = [{uri: 'sip:' + self_account + '@' + config.localIp + ':' + upward.self_port}];
            // retTrying.uri = upwardUri;
            // sip.send(retTrying);
            const localUdpPort = util.freeUdpPort(targetCamera.camera_id, 1);

            // 对 t 进行解析
            let startTime, endTime;
            if(s === 'Playback'){
                const array = t.split(' ');
                startTime = moment(parseInt(array[0])*1000);
                endTime = moment(parseInt(array[1])*1000);
            }
            // 在pushArray里放要推送的信息
            deviceCache.pushArray[pushKey] = {
                // processId:processId,
                localUdpPort: localUdpPort,
                targetIp: targetIp,
                targetPort: targetPort,
                playing: false,
                rtsp_url: targetCamera.mrl,
                lasttime: new Date(),
                description: targetCamera.description,
                s,
                t,
                startTime,endTime
            };

            logger.info(TAG,'准备调用 videoAck,本地端口 = ', localUdpPort, '推流缓存', deviceCache.pushArray);

            await that.videoAck(rq, cseq, fromUri, toUri, via, callid, obj.y, localUdpPort,s, t, upwardUri);

        } else {
            //TODO:  返回通道不存在
            logger.error(TAG,'通道不存在');
        }
    },

    // 请求视频回应
    async videoAck(rq, cseq, fromUri, toUri, via, callid, y, localUdpPort, s, t, upwardUri) {
        // logger.info(TAG,'回应invite, res=',rq, cseq, fromUri, toUri, via, callid, y, localUdpPort, s, t);
        const content = "v=0\r\n" +
            "o=" + toUri.user + " 0 0 IN IP4 " + config.localIp + "\r\n" +
            `s=${s}\r\n` +
            "i=VCam Live Video\r\n" +
            "c=IN IP4 " + config.localIp + "\r\n" +
            `t=${t}\r\n` +
            "m=video " + localUdpPort + " RTP/AVP 96\r\n" +
            "a=sendonly\r\n" +
            "a=rtpmap:96 PS/90000\r\n" +
            "y=" + y + "\r\n"
        ;

        const { upward } =await clientUtils.generateClientParams();
        const res = sip.makeResponse(rq, 200, 'OK');
        res.content = content;
        res.uri = upwardUri;
        res.headers.contact =  [{uri: 'sip:' + upward.self_account + '@' + config.localIp + ':' + upward.self_port}];
        res.headers['content-type'] = 'APPLICATION/SDP';
        logger.info(TAG,'回应invite, res=', res, '推流缓存', deviceCache.pushArray);
        sip.send(res);
    },
}
